package com.wyw.function.learning.demo9;

import com.wyw.function.learning.common.Shop;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @Title   去除阻塞测试
 * @Description     如果进行的是计算密集型的操作，并且没有I/O，推荐使用Stream接口，实现简单，效类也是最高的（如果所有的线程都是计算密集型的，那就没有必要创建比处理器核数多的线程）
 *                  并行的工作单元还涉及等待I/O操作（包括网络连接等待），那么使用CompletableFuture灵活性更好，一句等待/计算时间，或者W/C的比率设定需要使用的线程数，不使用Stream流的另一个原因，如果处理流中发生了I/O等待，流的延迟特性会让我们很难判断到底什么时候触发了等待
 * @Author Mr Wu yewen.wu.china@gmail.com
 * Update History:
 * Author        Time            Content
 */
public class DemoClient23 {

//    static final List<Shop> shops =
//            Arrays.asList(
//                    new Shop("wyw"),
//                    new Shop("hello"),
//                    new Shop("one"),
//                    new Shop("two")
//            );

    static final List<Shop> shops =
            Arrays.asList(
                    new Shop("wyw"),
                    new Shop("hello"),
                    new Shop("one"),
                    new Shop("two"),
                    new Shop("three"),
                    new Shop("four"),
                    new Shop("five"),
                    new Shop("six"),
                    new Shop("seven"),
                    new Shop("eight"),
                    new Shop("nine"),
                    new Shop("ten")
            );

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
//        List<String> prices = findPrices(shops, "Test");
//        List<String> prices = findPricesParallel(shops, "Test");
//        List<String> prices = findPricesAsync(shops, "Test");
//        List<String> prices = findPricesParallelAsync(shops, "Test");
        List<String> prices = findPricesCustom(shops, "Test");
        System.out.println(System.currentTimeMillis() - start + ":ms");
        for (String price:prices) {
            System.out.println(price);
        }
    }

    // 8s
    public static List<String> findPrices(List<Shop> shops, String product) {
        return shops.stream().map(shop -> {
            return ("shopName:" + shop.getShopName() + ", price:" + shop.getPrice(product));
        }).collect(Collectors.toList());
    }

    // 2s
    public static List<String> findPricesParallel(List<Shop> shops, String product) {
        return shops.parallelStream().map(shop -> {
            return ("shopName:" + shop.getShopName() + ", price:" + shop.getPrice(product));
        }).collect(Collectors.toList());
    }

    //1s
    public static List<String> findPricesAsync(List<Shop> shops, String product) {
        List<CompletableFuture<String>> collect = shops.stream().map(shop -> CompletableFuture.supplyAsync(() -> {
            try {
                return "shopName:" + shop.getShopName() + ", price:" + shop.getPriceAsync2(product).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return null;
        })).collect(Collectors.toList());
        return collect.stream().map(CompletableFuture::join).collect(Collectors.toList());
    }

    public static List<String> findPricesParallelAsync(List<Shop> shops, String product) {
        List<CompletableFuture<String>> collect = shops.parallelStream().map(shop -> CompletableFuture.supplyAsync(() -> {
            try {
                return "shopName:" + shop.getShopName() + ", price:" + shop.getPriceAsync2(product).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return null;
        })).collect(Collectors.toList());
        return collect.stream().map(CompletableFuture::join).collect(Collectors.toList());
    }

    public static List<String> findPricesCustom(List<Shop> shops, String product) {
        Executor service = Executors.newFixedThreadPool(Math.min(shops.size(), 100), r -> {
            Thread thread = new Thread(r);
            thread.setDaemon(true);
            return thread;
        });

        List<CompletableFuture<String>> collect = shops.stream().map(shop -> CompletableFuture.supplyAsync(() -> {
            try {
                return "shopName:" + shop.getShopName() + ", price:" + shop.getPriceAsync2(product).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return null;
        }, service)).collect(Collectors.toList());
        return collect.stream().map(CompletableFuture::join).collect(Collectors.toList());
    }
}
